/*
 *  Copyright 2002 by Texas Instruments Incorporated.
 *  All rights reserved. Property of Texas Instruments Incorporated.
 *  Restricted rights to use, duplicate or disclose this code are
 *  granted through contract.
 *  
 */
/*
 *  ======== thrCapture.c ========
 */
#include <std.h>
#include <string.h>

// DSP/BIOS includes
#include <tsk.h>

// CSL includes
#include <csl_dat.h>

// RF5 module includes
#include <chan.h>
#include <icell.h>
#include <scom.h>
#include <icc_linear.h>
#include <utl.h>

// DDK module
#include <fvid.h>
#include <edc.h>
#include <vport.h>
#include <vportcap.h>
#include <tvp51xx.h>    
                      
#include <csl_vphal.h>                      
#include <evmdm642.h>

#include <evmdm642_capParamsSDTVDefault.h>

// application includes
#include "appResources.h"
#include "appThreads.h"

// Thread include
#include "thrCapture.h"

//pragmas for buffers
#pragma DATA_SECTION(int_mem_temp, ".INTPROCBUFF");
#pragma DATA_ALIGN(int_mem_temp, MEMALIGN);

//Temp buffer for 422 to 420
unsigned char int_mem_temp[720];

static Void yuv422to420(char *frameIn[], char *frm_out[],
                  int width, int height, int pitch);

//Buffer for interleaved captured image
FVID_Handle  capChan;
FVID_Frame *capFrameBuf;

/* caputure configuration parameters */
/* embedded sync mode is recommended as it offers better re-sync capability */
VPORT_PortParams EVMDM642_vCapParamsPort 
  = EVMDM642_CAP_PARAMS_PORT_EMBEDDED_DEFAULT;

#ifdef _NTSC
static VPORTCAP_Params EVMDM642_vCapParamsChan 
  = EVMDM642_CAP_PARAMS_CHAN_EMBEDDED_DEFAULT(SIF);
  
static TVP51XX_ConfParams EVMDM642_vCapParamsTVP5146 
  = EVMDM642_CAP_PARAMS_TVP51XX_EMBEDDED_DEFAULT(NTSC601, COMPOSITE, 0);

#elif defined _PAL
static VPORTCAP_Params EVMDM642_vCapParamsChan 
  = EVMDM642_CAP_PARAMS_CHAN_EMBEDDED_DEFAULT(CIF);
  
static TVP51XX_ConfParams EVMDM642_vCapParamsTVP5146 
  = EVMDM642_CAP_PARAMS_TVP51XX_EMBEDDED_DEFAULT(PAL601, COMPOSITE, 0);
#endif

/*
 *  ======== thrCaptureInit ========
 *
 */
Void thrCaptureInit() 
{
    SCOM_Handle scomReceive;
    int             status;
    
    /* create your receiving SCOM queue */
    //scomReceive = SCOM_create( "scomCapture", &SCOM_ATTRS );
    //UTL_assert( scomReceive != NULL);
    
    EVMDM642_vCapParamsChan.segId = EXTERNALHEAP;
    EVMDM642_vCapParamsTVP5146.hI2C = EVMDM642_I2C_hI2C;
    
    capChan = FVID_create("/VP0CAPTURE/A/0",
        IOM_INPUT, &status, (Ptr)&EVMDM642_vCapParamsChan, NULL);

    FVID_control(capChan, VPORT_CMD_EDC_BASE+EDC_CONFIG, (Ptr)&EVMDM642_vCapParamsTVP5146);
    
    scomReceive = SCOM_create("scomCapture", &SCOM_ATTRS);
    UTL_assert( scomReceive != NULL);
}


/*
 *  ======== thrCaptureStartup ========
 *
 */
Void thrCaptureStartup() 
{    
    FVID_control(capChan, VPORT_CMD_START, NULL);
}

/*
 *  ======== thrCaptureRun ========
 *
 *  Main function of capture thread.
 */
Void thrCaptureRun()
{
    SCOM_Handle  scomReceive, scomSend;
    Int counter = 0;
    char *inBuf[3];
    char *outBuf[3];
    
    UTL_logDebug1("thrCaptureRun: task = 0x%x", TSK_self());

    // create the SCOM links (one for receiving and another for sending) 
    scomReceive = SCOM_open( "scomCapture" );
    scomSend    = SCOM_open( "scomToProcessFromCapture" );

    UTL_assert( scomReceive != NULL );
    UTL_assert( scomSend != NULL );
    
    FVID_alloc(capChan, &capFrameBuf);

    
    while (TRUE) { 
        ScomCapToProc *scombufCap;

        //Counter for measuring frames/sec - use with stopwatch
        counter++;
    
        // get the structure describing destination channels
        scombufCap = SCOM_getMsg( scomReceive, SYS_FOREVER );        

		//convert 422 to 420
        inBuf[Y] = capFrameBuf->frame.iFrm.y1;
        inBuf[CR] = capFrameBuf->frame.iFrm.cr1;
        inBuf[CB] = capFrameBuf->frame.iFrm.cb1;
        
        outBuf[Y] = scombufCap->bufYCRCB[Y];
        outBuf[CR] = scombufCap->bufYCRCB[CR];
        outBuf[CB] = scombufCap->bufYCRCB[CB];
        
        yuv422to420(inBuf, outBuf, PROCF_WIDTH, CAPF_HEIGHT, CAPF_WIDTH);

        // Calculate how long it takes to capture + display one frame
        UTL_stsPeriod( stsCycleTime );

        // send the now full buffer to Process
        SCOM_putMsg( scomSend, scombufCap );
        
        FVID_exchange(capChan, &capFrameBuf);	//Passes full buffer, recieves empty
    }       
}

/*
 *  ======== yuv422to420 ========
 *
 *  Input for this func will 4:2:2 data. This function
 *  will convert the data to 4:2:0 and will also reformat
 *  the data to be contiguous at MB level.
 */

void yuv422to420( char *frameIn[], char *frm_out[],
                  int width, int height, int pitch)
{
    char *pSrcY = frameIn[0];
    char *pSrcU = frameIn[1];
    char *pSrcV = frameIn[2];

    char *pDestY = frm_out[0];
    char *pDestU = frm_out[1];
    char *pDestV = frm_out[2];

    unsigned int id;
	unsigned int i;
    int crPitch = ((pitch >> 1) + 7) & (~7);

#if 1
    for( i = 0; i < height; i++)
    {
        id = DAT_copy(pSrcY + (i * pitch), int_mem_temp, width);
        id = DAT_copy(int_mem_temp,      pDestY + (i * width),  width);
    }

    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcU + (i * (crPitch << 1)), int_mem_temp, width >> 1);
        id = DAT_copy(int_mem_temp,      pDestU + (i * (width >> 1)),  width >> 1);
    }

    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcV + (i * (crPitch << 1)), int_mem_temp, width >> 1);
        id = DAT_copy(int_mem_temp,      pDestV + (i * (width >> 1)),  width >> 1);
    }
#else

	DAT_copy2d(DAT_2D1D, pSrcY, pDestY, width, height, pitch);
	DAT_copy2d(DAT_2D1D, pSrcU, pDestU, width >> 1, height >> 1, crPitch << 1);
	id = DAT_copy2d(DAT_2D1D, pSrcV, pDestV, width >> 1, height >> 1, crPitch << 1);
#endif

    DAT_wait(id);

    return ;
}


